#include "thread_pool.h"
#include <cassert>
#include "functional"


ThreadPool::ThreadPool() : threadNum_(0), running_(false) {}

ThreadPool::~ThreadPool() {
    if (running_) stop();
}

void ThreadPool::setThreadNum(int threadNum) {
    assert(threadNum >= 0);
    threadNum_ = threadNum;
}

void ThreadPool::start() {
    for (int i = 0; i < threadNum_; ++i) {
        threads_.emplace_back(new std::thread(std::bind(&ThreadPool::threadPoolRunFunc, this)));
    }
    running_ = true;
}

void ThreadPool::stop() {
    running_ = false;
    notEmpty_.notify_all();
    for (auto &thread : threads_) {
        thread->join();
    }
}

void ThreadPool::addTask(ThreadTask task) {
    if (!running_) start();
    if (threads_.empty()) {
        task();
    } else {
        std::unique_lock<std::mutex> lock(mutex_);
        tasks_.emplace(std::move(task));
        notEmpty_.notify_one();
    }
}

size_t ThreadPool::queueSize() const {
    std::unique_lock<std::mutex> lock(mutex_);
    return tasks_.size();
}

void ThreadPool::threadPoolRunFunc() {
    while (true) {
        std::unique_lock<std::mutex> lock(mutex_);
        notEmpty_.wait(lock, [&]() { return !tasks_.empty() || !running_; });
        if (!running_) return;
        auto task(std::move(tasks_.front()));
        tasks_.pop();
        if (task) task();
    }
}